package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseModel;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private CourseMarketService courseMarketService;


    /*
    * 分析：
    *   1.是否开启事务
    *       不需要（查询不需要开启事务）
    *   2.判断关键的数据
    *       分页数据
    *           判断是否是非法数据
    *       查询条件
    *           无数据：所有数据
    *           有数据：添加条件数据
    *   3.创建出分页数据对象
    *       Page
    *   4.查询结果数据
    *   5.封装结果数据内容并返回
    *       PageVO
    * */
    public PageVO queryCourseList(PageRequestParams params, QueryCourseModel model,Long companyId) {

        // 1.是否开启事务
        //      不需要（查询不需要开启事务）
        //  2.判断关键的数据
        //      分页数据
        //          判断是否是非法数据(pageNo，pageSize)
        // 2.1 分页数据
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }


        //      查询条件
        //          无数据：所有数据
        //          有数据：添加条件数据
        // 2.2 查询条件
        // select * from course_base where course_name like ? and audit_status = ?

        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

        String courseName = model.getCourseName();
        // 完整版
        // if (StringUtil.isNotBlank(courseName)) {
        //     queryWrapper.like(CourseBase::getName, courseName);
        // }

        String auditStatus = model.getAuditStatus();
        // if (StringUtil.isNotBlank(auditStatus)) {
        //     queryWrapper.eq(CourseBase::getAuditStatus, auditStatus);
        // }

        // 简版
        queryWrapper.like(StringUtil.isNotBlank(courseName),CourseBase::getName, courseName);
        queryWrapper.eq(StringUtil.isNotBlank(auditStatus),CourseBase::getAuditStatus, auditStatus);
        queryWrapper.eq(CourseBase::getCompanyId, companyId);


        //  3.创建出分页数据对象
        //      Page
        Page<CourseBase> basePage = new Page<>(params.getPageNo(),params.getPageSize());


        //  4.查询结果数据
        Page<CourseBase> page = this.page(basePage, queryWrapper);

        List<CourseBase> records = page.getRecords();
        long total = page.getTotal();

        // 代码
        List<CourseBaseDTO> dtos = Collections.EMPTY_LIST;
        // 使用mapstruct转换器将pos转为dtos
        if (!(CollectionUtils.isEmpty(records))) {
            dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }


        //  5.封装结果数据内容并返回
        //      PageVO
        PageVO pageVO = new PageVO(dtos,total,params.getPageNo(),params.getPageSize());

        return pageVO;
    }

    /*
    * 业务的分析：
    *   1.是否要开启事务
    *       新增操作需要开启事务
    *   2.判断关键数据
    *       数据库表的约束: companyId,name,mt,st,grade,teachmode,auditstatus
    *       前端页面中的非空（红色*）: users,charge
    *       如果课程是收费：价格必须存在
    *   3.将dto数据转为po数据
    *   4.对新增的课程添加审核的默认状态：未提交
    *   5.保存数据并判断是否保存成功
    *   6.保存课程营销数据并判断是否成功
    *   7.将保存成功的数据转为dto数据并返回
    * */
    @Transactional
    public CourseBaseDTO createCourseBase(CourseBaseDTO dto) {

        //1.是否要开启事务
        //     新增操作需要开启事务
        // 2.判断关键数据
        //     数据库表的约束: companyId,name,mt,st,grade,teachmode,auditstatus
        //     前端页面中的非空（红色*）: users,charge
        verifyCourseMsg(dto);

        // 如果课程是收费：价格必须存在
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())) {

            if (ObjectUtils.isEmpty(dto.getPrice())) {
                throw new RuntimeException("收费课程价格不能为空");
            }

        }


        // 3.将dto数据转为po数据
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);


        // 4.对新增的课程添加审核的默认状态：未提交
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());



        // 5.保存数据并判断是否保存成功
        // PS: MP 将数据保存到数据库后，会将id值赋值会封装类中（courseBase）
        boolean result = this.save(courseBase);

        if (!result) {
            throw new RuntimeException("保存课程基础信息失败");
        }

        // 6.保存课程营销数据并判断是否成功
        CourseMarket courseMarket = new CourseMarket();

        courseMarket.setCourseId(courseBase.getId());
        courseMarket.setCharge(dto.getCharge());
        courseMarket.setPrice(dto.getPrice());

        boolean marketResult = courseMarketService.save(courseMarket);


        if (!marketResult) {
            throw new RuntimeException("保存课程营销数据失败");
        }


        // 7.将保存成功的数据转为dto数据并返回
        CourseBaseDTO resultDto = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        resultDto.setCharge(courseMarket.getCharge());
        resultDto.setPrice(courseMarket.getPrice());


        return resultDto;
    }

    /*
    * 校验课程的关键数据
    * */
    private void verifyCourseMsg(CourseBaseDTO dto) {
        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
            // 如果业务数据不完整：抛出异常信息--业务异常（可以终止程序运行，异常可以填写错误信息--业务错误信息）
            throw new RuntimeException("公司id不能为空");
        }

        if (StringUtil.isBlank(dto.getName())) {
            throw new RuntimeException("课程名称不能为空");
        }

        if (StringUtil.isBlank(dto.getMt())) {
            throw new RuntimeException("课程大分类不能为空");
        }

        if (StringUtil.isBlank(dto.getSt())) {
            throw new RuntimeException("课程小分类不能为空");
        }

        if (StringUtil.isBlank(dto.getGrade())) {
            throw new RuntimeException("课程等级不能为空");
        }

        if (StringUtil.isBlank(dto.getTeachmode())) {
            throw new RuntimeException("课程教学模式不能为空");
        }

        if (StringUtil.isBlank(dto.getUsers())) {
            throw new RuntimeException("使用人群不能为空");
        }

        if (StringUtil.isBlank(dto.getCharge())) {
            throw new RuntimeException("课程收费不能为空");
        }
    }


    /*
    * 业务分析：
    *   1.判断关键数据
    *       courseBaseId  companyId
    *   2.判断业务数据
    *       课程基本信息
    *           判断课程信息是否存在
    *           判断课程是否删除
    *           判断是否是同一家机构
    *   3.转换po数据转为dto数据
    *       课程基础信息
    *       课程营销
    *
    *   4.将dto数据进行返回
    * */
    public CourseBaseDTO getCourseBaseById(Long courseBaseId, Long companyId) {

        // 1.判断关键数据
        //      courseBaseId  companyId
        if (ObjectUtils.isEmpty(courseBaseId)||
                ObjectUtils.isEmpty(companyId)
        ) {
            throw new RuntimeException("关键数据不能为空");
        }



        //  2.判断业务数据
        //      课程基本信息
        //          判断课程信息是否存在,判断是否是同一家机构， 判断课程是否删除

        // 麻烦
        // CourseBase courseBase = this.getById(courseBaseId);


        // 检查检验数据：判断课程信息是否存在,判断是否是同一家机构， 判断课程是否删除
        CourseBase courseBase = getCourseBaseByIdAndCompanyId(courseBaseId, companyId);

        if (ObjectUtils.isEmpty(courseBase)) {
            throw new RuntimeException("课程信息不存在");
        }


        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())) {
            throw new RuntimeException("课程信息已被删除");
        }


        //  3.转换po数据转为dto数据
        //      课程基础信息
        //      课程营销
        CourseBaseDTO dto = CourseBaseConvert.INSTANCE.entity2dto(courseBase);

        LambdaQueryWrapper<CourseMarket> marketQueryWrapper = new LambdaQueryWrapper<>();
        marketQueryWrapper.eq(CourseMarket::getCourseId, courseBaseId);

        CourseMarket market = courseMarketService.getOne(marketQueryWrapper);


        dto.setCharge(market.getCharge());
        dto.setPrice(market.getPrice());


        //  4.将dto数据进行返回
        return dto;
    }

    private CourseBase getCourseBaseByIdAndCompanyId(Long courseBaseId, Long companyId) {
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(CourseBase::getId, courseBaseId);
        queryWrapper.eq(CourseBase::getCompanyId, companyId);
        // queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCodeInt());

        CourseBase courseBase = this.getOne(queryWrapper);
        return courseBase;
    }


    /*
    * 业务分析：
    *   1.判断关键数据
    *      数据库表的约束: companyId,name,mt,st,grade,teachmode,auditstatus
           前端页面中的非空（红色*）: users,charge
           如果课程是收费：价格必须存在
           修改的数据必有Id值

    *    2.判断业务数据
    *       课程基础信息
    *           判断是否存在
    *           判断课程是否删除
    *           判断课程是否是同一家教学机构
    *           判断课程的审核状态
    *
    *    3.修改课程数据
    *       课程基础信息数据
    *       课程营销数据
    *
    *   4.将结果内容返回（po-->dto）
    *
    * */
    @Transactional
    public CourseBaseDTO modifyCourseBaseById(CourseBaseDTO dto) {


        // 1.判断关键数据
        //     数据库表的约束: companyId,name,mt,st,grade,teachmode,auditstatus
        //     前端页面中的非空（红色*）: users,charge
        //     如果课程是收费：价格必须存在
        //     修改的数据必有Id值
        verifyCourseMsg(dto);

        Long courseBaseId = dto.getCourseBaseId();
        if (ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("课程id不能为空");
        }



        //   2.判断业务数据
        //      课程基础信息
        //          判断是否存在，判断课程是否是同一家教学机构
        //          判断课程是否删除
        //          判断课程的审核状态
        Long companyId = dto.getCompanyId();


        CourseBase courseBase = getCourseBaseByIdAndCompanyId(courseBaseId, companyId);

        if (ObjectUtils.isEmpty(courseBase)) {
            throw new RuntimeException("课程信息不存在");
        }

        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())) {
            throw new RuntimeException("课程信息已被删除");
        }

        String auditStatus = courseBase.getAuditStatus();

        if (CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)
        ) {
            throw new RuntimeException("课程审核状态异常");
        }



        //   3.修改课程数据
        //      课程基础信息数据
        //      课程营销数据
        CourseBase po = CourseBaseConvert.INSTANCE.dto2entity(dto);

        boolean courseBaseResult = this.updateById(po);

        if (!courseBaseResult) {
            throw new RuntimeException("修改课程信息失败");
        }

        // updateWrapper
        // update course_market set price = xxx, charge = xxx where course_id = xxxx
        LambdaUpdateWrapper<CourseMarket> updateWrapper = new LambdaUpdateWrapper<>();

        updateWrapper.set(CourseMarket::getCharge,dto.getCharge());
        updateWrapper.set(CourseMarket::getPrice,dto.getPrice());
        updateWrapper.eq(CourseMarket::getCourseId,courseBaseId);

        boolean marketResult = courseMarketService.update(updateWrapper);

        if (!marketResult) {
            throw new RuntimeException("修改课程营销数据失败");
        }


        //  4.将结果内容返回（po-->dto）
        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(po);

        resultDTO.setCharge(dto.getCharge());
        resultDTO.setPrice(dto.getPrice());


        return resultDTO;
    }
}
